<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script>
    // 21-05-20- 北京海淀 

    //对闭包的看法 为什么使用闭包 说一下闭包原理以及应用场景
    
    //什么是闭包 ?
    //函数执行后 返回的结果是一个内部函数 并被外部变量所引用 如果内部函数持有被执行函数作用域的变量
    //即形成了闭包 
   
    //可以在内部函数 访问到外部函数作用域

    //使用闭包? 
    //1* 可以读取函数中的变量 
    //2* 可以将函数中的变量存储在内存中 保护变量不被污染
    //注意! 因为闭包会把函数中的变量值存储在内存中 回对内存有消耗 所以不能瞎用闭包 否则会影响性能 内存泄漏 
    //当我们不使用闭包时 要及时释放内存 可将内层函数对象的变量赋值 为null

    //闭包原理?
    //函数执行分为两个阶段 (预编译阶段)+(执行阶段)
    //* 在预编译阶段 如果发现内部函数 使用了外部函数的变量 则会在内存中创建一个闭包 对象并保存对应变量值
    //  如果已经存在闭包 则只需要增加对应属性值即可  
    //  执行完后 函数执行上下文 会被销毁 函数对闭包 对象的引用也会被销毁 使其内部函数 还持用该 闭包的引用 
    //  所以内部函数 可以继续使用外部函数中的变量 

    //优点?
    //  可以从内部函数访问到外部函数作用域中的变量 切访问到的变量长期驻扎在内存中 可供之后使用 
    //  避免变量污染全局 
    //  对处理速度有影响 可能获取到意外的值 

    //应用场景? 看案例 
    // 应用场景1  
        //典型应用是模块封装 在各模块规范出现之前 都素hi用这个方式 防止变量污染全局的
        var Yideng = (function () {
            //这样声明为模块私有变量，外界无法直接访问
            var foo = 0;
            function Yideng() {}
            Yideng.prototype.bar = function bar() {
                return foo;
            };
            return Yideng;
        }());

    //应用场景2 
    //在循环中 创建闭包 防止得到意外值     
    //demo代码 无论那个元素触发事件 都会弹出3  因为函数执行后引用i是同一个i  而i结束循环后就是3
    // for (var i = 0; i < 3; i++) {
    //     document.getElementById('id' + i).onfocus = function() {
    //         alert(i);
    // };
    // }

    //可用闭包解决
    function makeCallback(num) {
        return function() {
            alert(num);
        };
    }
    // for (var i = 0; i < 3; i++) {
    //         document.getElementById('id' + i).onfocus = makeCallback(i);
    // }

    function fun(){
        var i = 0;
        function f(){
            console.log(i++);
        }
        return f
    }
    var f = fun();
    f();
    f();
    f();

</script>